<?php
/**
 * This file defines the exception class {@see \BF\ArgumentException}.
 *
 * @author     Kado <ulfikado@gmail.com>
 * @category   Beluga PHP5.3+ Framework
 * @package    BF\Core
 * @since      2015-01-17 14:29
 * @subpackage Exceptions
 * @version    0.1
 */

namespace BF
{

   /**
    * This Exception is used, if a function or method argument is wrong/invalid
    *
    * The class extends from {@see \BF\Exception}
    *
    * @since  v0.1
    */
   class ArgumentException extends \BF\Exception
   {

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R O T E C T E D   F I E L D S   - - - - - - - - - - - - - - - - - - - -">

      /**
       * The argument name.
       *
       * @var string
       */
      protected $argumentName;

      /**
       * The function or method name.
       *
       * @var string
       */
      protected $functionName;

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - >   P U B L I C   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - -">

      /**
       * Inits a new instance.
       *
       * @param string     $arg      The argument/parameter name
       * @param mixed      $value    The argument/parameter value
       * @param string     $message  The error message (default=null)
       * @param int        $code     The error code (default=\E_USER_ERROR)
       * @param \Exception $previous A optional previous exception
       */
      public function __construct( $arg, $value, $message = null, $code = \E_USER_ERROR, \Exception $previous = null )
      {
         $trace = \debug_backtrace();
         $lidx  = \count( $trace ) - 1;

         $fn = ( empty( $trace[ $lidx ][ 'class' ] )    ? '' : $trace[ $lidx ][ 'class' ] )
            .  ( empty( $trace[ $lidx ][ 'type' ] )     ? '' : $trace[ $lidx ][ 'type' ] )
            .  ( empty( $trace[ $lidx ][ 'function' ] ) ? '' : $trace[ $lidx ][ 'function' ] );

         parent::__construct(
            'Argument $' . \ltrim( $arg, '$' )
               .  ( empty( $fn ) ? '' : ' of ' . $fn . '(…)' )
               .  ' uses a invalid value of type '
               .  self::GetTypeStr( $value )
               .  ( empty( $message ) ? '' : ( ' ' . $message ) ),
            $code,
            $previous
         );

         $this->argumentName = $arg;
         $this->functionName = $fn;
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" * *   G E T T E R S   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *">

      /**
       * Returns the name of the error argument/parameter.
       *
       * @return string
       */
      public final function getArgumentName()
      {
         return $this->argumentName;
      }

      /**
       * Returns the value of the error argument/parameter.
       *
       * @return mixed
       */
      public final function getFunctionName()
      {
         return $this->functionName;
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R O T E C T E D   S T A T I C   M E T H O D S   - - - - - - - - - - - -">

      /**
       * Returns a string, representing the permited value.
       *
       * @param  mixed $value
       * @return string
       */
      protected static function GetTypeStr( $value )
      {
         if ( \is_null( $value ) )
         {
            return 'NULL';
         }
         if ( \is_resource( $value ) )
         {
            return \get_resource_type( $value ) . '-Resource';
         }
         if ( \is_string( $value ) )
         {
             if ( \strlen( $value ) > 128 )
             {
                 return 'string with value (' . \substr( $value, 0, 126 ) . '…)';
             }
             return 'string with value (' . $value . ')';
         }
         if ( \is_bool( $value ) )
         {
            return 'boolean with value (' . ( $value ? 'true' : 'false' ) . ')';
         }
         if ( \is_int( $value ) )
         {
            return 'integer with value (' . $value . ')';
         }
         if ( \is_float( $value ) )
         {
            return 'float with value (' . $value . ')';
         }
         if ( \is_double( $value ) )
         {
            return 'double with value (' . $value . ')';
         }
         if ( \is_array( $value ) )
         {
            return 'Array: ' . \print_r( $value, true );
         }
         if ( \is_object( $value ) )
         {
            return \get_class( $value ) . ' object: ' . \print_r( $value, true );
         }
         return \gettype( $value );
      }

      # </editor-fold>

   }

}

